#region File information

/**
 * File: Mesh.cs
 * Date: 08-03-2008
 * Auth: Jan-Jaap Severs
 * 
 * Desc: The Mesh class represents a renderable (and possibly animated) object in the game world.
 */

#endregion

#region Using statements

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Gremlin.Game;
using System.Collections;
using Gremlin.Components;
using Microsoft.Xna.Framework;

#endregion

namespace Gremlin.Graphics
{
    /// <summary>
    /// The Mesh class represents a renderable (and possibly animated) object in the game world.
    /// </summary>
    public class Mesh : GameObject
    {
        #region Member variables

        // The 3D model for this Mesh.
        protected Model _model;

        #endregion

        /// <summary>
        /// Creates a new mesh based on a modelname.
        /// </summary>
        /// <param name="game">The Game class instance.</param>        
        /// <param name="content">The ContentManager for the game.</param>
        /// <param name="modelName">The name of the model to load.</param>
        public Mesh(Microsoft.Xna.Framework.Game game, ContentManager content, string modelName)
            : base(game)
        {
            // Load the model through the content pipeline.
            _model = content.Load<Model>(modelName);

            Initialize();
        }

        /// <summary>
        /// Creates a new mesh based on info from a leveldescription.
        /// </summary>
        /// <param name="game">The Game class instance.</param>
        /// <param name="content">The ContentManager for the game.</param>
        /// <param name="meshInfo">The info about which mesh to load, as read from the leveldescription file.</param>
        public Mesh(Microsoft.Xna.Framework.Game game, ContentManager content, LevelDescription.MeshInfo meshInfo)
            : base(game)
        {
            // Load the model through the content pipeline.
            _model = content.Load<Model>(meshInfo.ResourceName);

            Initialize();

            // Place and orientate the model as specified by the leveldescription file. Do this after calling
            // Initialize(), because GameObject::Initialize will reset position and rotation to identity values.
            _position = meshInfo.StartPosition;
            _rotation = meshInfo.StartRotation;
        }

        /// <summary>
        /// Initializes the bounding boxes and animations for this Mesh.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            // Generate bounding spheres for each of the Mesh's sub-objects.
            foreach (ModelMesh modelMesh in _model.Meshes)
                _boundingSphere = BoundingSphere.CreateMerged(_boundingSphere, modelMesh.BoundingSphere);
            
        }

        /// <summary>
        /// Renders our model to the screen.
        /// </summary>        
        public virtual void Draw()
        {
            // Get the current camera from the Game's services.
            Camera cam = ((CameraProvider)_game.Services.GetService(typeof(ICameraService))).Camera;

            if (cam == null)
                return;            

            // Render all of the model's sub-objects.
            foreach (ModelMesh mesh in _model.Meshes)
            {
                foreach (Effect ef in mesh.Effects)
                {
                    ef.Parameters["View"].SetValue(cam.ViewMatrix);
                    ef.Parameters["Projection"].SetValue(cam.ProjMatrix);
                    ef.Parameters["World"].SetValue(_world);
                                        
                    if (ef is BasicEffect)
                    {
                        BasicEffect effect = (BasicEffect)ef;
                        effect.EnableDefaultLighting();
                        effect.DirectionalLight0.Direction = new Vector3(0, -0.5f, -0.5f);
                        effect.DirectionalLight1.Enabled = false;
                        effect.DirectionalLight2.Enabled = false;
                        effect.AmbientLightColor = Color.Black.ToVector3();
                        effect.EmissiveColor = Color.Black.ToVector3();
                    }
                }

                mesh.Draw();
            }
        }
    }

    /// <summary>
    /// A collection of Meshes.
    /// </summary>
    public class MeshCollection : CollectionBase
    {
        /// <summary>
        /// Adds a new Mesh to the collection.
        /// </summary>
        /// <param name="newMesh">The Mesh to add.</param>
        public virtual void Add(Mesh newMesh)
        {
            List.Add(newMesh);
        }

        /// <summary>
        /// Retrieves a Mesh from the collection.
        /// </summary>
        /// <param name="index">The index of the Mesh to retrieve.</param>
        /// <returns>The Mesh at the specified index.</returns>
        public virtual Mesh this[int index]
        {
            get { return (Mesh)List[index]; }
        }
    }
}
